#include <stdio.h>

#include "aliyun_iot_mqtt_common.h"
#include "aliyun_iot_mqtt_client.h"
#include "aliyun_iot_common_datatype.h"
#include "aliyun_iot_common_error.h"
#include "aliyun_iot_common_log.h"
#include "aliyun_iot_auth.h"
#include "aliyun_iot_platform_pthread.h"
#include "aliyun_iot_platform_memory.h"
#include "xrj_mqtt_client.h"
#include "gsm_function.h"
#include "xrj_protocol.h"
#include "wifi_function.h"

//#define HOST_NAME      "192.168.100.176:8080/xrj-api-web/api/device/auth/"

//用户需要根据设备信息完善以下宏定义中的四元组内容
//#define PRODUCT_KEY    ""
//#define PRODUCT_SECRET ""
//#define DEVICE_NAME    "d34922b84e094d949bf0a167bea5bc97"
//#define DEVICE_SECRET  ""

//以下三个TOPIC的宏定义不需要用户修改，可以直接使用
//IOT HUB为设备建立三个TOPIC：update用于设备发布消息，error用于设备发布错误，get用于订阅消息
//#define TOPIC_UPDATE         "/"PRODUCT_KEY"/"DEVICE_NAME"/update"
//#define TOPIC_ERROR          "/"PRODUCT_KEY"/"DEVICE_NAME"/update/error"
//#define TOPIC_GET            "/"PRODUCT_KEY"/"DEVICE_NAME"/get"

//#define TOPIC_UPDATE         "/update"
//#define TOPIC_ERROR          "/"PRODUCT_KEY"/"DEVICE_NAME"/update/error"
//#define TOPIC_GET            "/get/#"


//#define TOPIC_UPDATE         "/QvxU3MgU6wY/d34922b84e094d949bf0a167bea5bc97/update"
//#define TOPIC_ERROR          "/"PRODUCT_KEY"/"DEVICE_NAME"/update/error"
//#define TOPIC_GET            "/QvxU3MgU6wY/d34922b84e094d949bf0a167bea5bc97/get"

//#define TOPIC_UPDATE         "/"XRJ_PRODUCT_KEY"/"XRJ_DEVICE_NAME"/update"
//#define TOPIC_ERROR          "/"XRJ_PRODUCT_KEY"/"XRJ_DEVICE_NAME"/update/error"
//#define TOPIC_GET            "/"XRJ_PRODUCT_KEY"/"XRJ_DEVICE_NAME"/get"

//#define MSG_LEN_MAX 1024



/**Number of publish thread*/
#define MAX_PUBLISH_THREAD_COUNT 2
INT32	FLAG_Net_Type = 0;	


UINT32	usr_subAck_Timeout = 0;
unsigned char MSG_Write_Buf[MSG_LEN_MAX];
unsigned char MSG_Read_Buf[MSG_LEN_MAX];
unsigned char MSG_Publish_Buf[MSG_LEN_MAX]; 
struct BOARD_INFO	XRJ_BOARD_INFO;

void MCU_Reset(void)
{

	OSTimeDlyHMSM (0,0,0,100);
	__set_FAULTMASK(1);     
	NVIC_SystemReset();
		
}




//callback of publish
static void messageArrived(MessageData *md)
{
//    char msg[MSG_LEN_MAX] = {0};

    MQTTMessage *message = md->message;
    if(message->payloadlen > MSG_LEN_MAX - 1)
    {
        printf("process part of receive message\n");
        message->payloadlen = MSG_LEN_MAX - 1;
    }
	MQTT_RxMsg_Proc((uint8_t *)message->payload,message->payloadlen);
//	memcpy(msg,message->payload,message->payloadlen);
//	XRJ_Receive_Proc((uint8_t *)msg,message->payloadlen);
//	printf("Message : %s\n", msg);
//		LCD_ShowString(30,200,210,16,16,msg);	
}

static void publishComplete(void* context, unsigned int msgId)
{
    printf("publish message is arrived,id = %d\n",msgId);
}

static void subAckTimeout(SUBSCRIBE_INFO_S *subInfo)
{
	usr_subAck_Timeout = 0xff;
    printf("msgId = %d,sub ack is timeout\n",subInfo->msgId);
}

void * pubThread(void*param)
{
    char buf[MSG_LEN_MAX] = { 0 };
    static int num = 0;
    int rc = 0 ;
    Client * client = (Client*)param;
    MQTTMessage message;

//    int msgId[5] = {0};

    static int threadID = 0;
    int id = threadID++;

    for(;;)
    {
        int i = 0;
        for(i = 0; i < 5; i++)
        {
            memset(&message,0x0,sizeof(message));
            sprintf(buf, "{\"message\":\"Hello World! threadId = %d, num = %d\"}",id,num++);
            message.qos = QOS1;
            message.retained = FALSE_IOT;
            message.dup = FALSE_IOT;
            message.payload = (void *) buf;
            message.payloadlen = strlen(buf);
            message.id = 0;
            rc = aliyun_iot_mqtt_publish(client, g_userInfo.PubTopic, &message);
            if (0 != rc)
            {
                printf("ali_iot_mqtt_publish failed ret = %d\n", rc);
            }
//            else
//            {
//                msgId[i] = message.id;
//            }

            aliyun_iot_pthread_taskdelay(5000);
        }

        aliyun_iot_pthread_taskdelay(1000);
    }

//    return NULL;
}




int singleThreadDemo()
{
    int rc = 0;
	int cnt = 0;
	INT32 cnt_Pub_False = 0;
//	unsigned char err = 0;	
/*-----HTTP认证	------------------------------------------------------------------------	
通过HTTP获取 g_userInfo的以下信息
	hostAddress：IP地址
	clientId：
	userName: 用户名
	password：密码
	port：端口号
****************************************************************************************/	
	for (cnt = 0; cnt < 3;	cnt++)
	{
			if (aliyun_iot_auth_XRJ() == SUCCESS_RETURN)
			{
					cnt =0xff;
					break;
			}		
	}		
	if (cnt != 0xff)
			return 0;
//-------------------------------------------------------------------------------------
	
//---MQTT部分---------------------------------------------------------------------------	
    Client client;
    memset(&client,0x0,sizeof(client));
    IOT_CLIENT_INIT_PARAMS initParams;
    memset(&initParams,0x0,sizeof(initParams));

    initParams.mqttCommandTimeout_ms = 2000;
    initParams.pReadBuf = MSG_Read_Buf;
    initParams.readBufSize = MSG_LEN_MAX;
    initParams.pWriteBuf = MSG_Write_Buf;
    initParams.writeBufSize = MSG_LEN_MAX;
    initParams.disconnectHandler = NULL;
    initParams.disconnectHandlerData = (void*) &client;
    initParams.deliveryCompleteFun = publishComplete;
    initParams.subAckTimeOutFun = subAckTimeout;
    rc = aliyun_iot_mqtt_init(&client, &initParams);
    if (0 != rc)
    {
        printf("aliyun_iot_mqtt_init failed ret = %d\n", rc);
        return rc;
    }
	//---添加默认订阅
	client.defaultMessageHandler = messageArrived;
	
    MQTTPacket_connectData connectParam;
    memset(&connectParam,0x0,sizeof(connectParam));
    connectParam.cleansession = 0;	//是否接收离线消息
    connectParam.MQTTVersion = 4;
    connectParam.keepAliveInterval = 60;
    connectParam.willFlag = 0;
			
		
		
		
    rc = aliyun_iot_mqtt_connect(&client, &connectParam);
    if (0 != rc)
    {
        aliyun_iot_mqtt_release(&client);
        printf("ali_iot_mqtt_connect failed ret = %d\n", rc);
        return rc;
    }
	
	XRJ_Protocol_MQTT_Init();
	countdown_ms(&client.ping_timer, client.connectdata.keepAliveInterval*1000);
	for (cnt = 0; cnt < 3; cnt++)
	{
		usr_subAck_Timeout = 0;	
		rc = aliyun_iot_mqtt_subscribe(&client, g_userInfo.SubTopic, QOS1, messageArrived);
		if (0 != rc)
		{
			aliyun_iot_mqtt_release(&client);
			printf("ali_iot_mqtt_subscribe failed ret = %d\n", rc);
			return rc;
		}

		do
		{
#if		MQTT_pThread_EN == 0	
			xrj_iot_mqtt_proc(&client,20);
#endif			
//			aliyun_iot_pthread_taskdelay(4);
			rc = aliyun_iot_mqtt_suback_sync(&client, g_userInfo.SubTopic, messageArrived);
		}while(rc != SUCCESS_RETURN);
		
		if (usr_subAck_Timeout == 0)
		{
			cnt = 0xff;
			break;
		}	
	}
	if (cnt != 0xff)
	{
		aliyun_iot_mqtt_release(&client);
		return 0;
	}	

    MQTTMessage message;
    memset(&message,0x0,sizeof(message));
 //   sprintf(buf, "{\"message\":\"Hello World\"}");
    message.qos = QOS1;
    message.retained = FALSE_IOT;
    message.dup = FALSE_IOT;
//    message.payload = (void *) buf;
//    message.payloadlen = strlen(buf);
    message.payload = (void *) NULL;
    message.payloadlen = 0;	
    message.id = 0;
//    printf("Test XXXXXXXXXXXXXXXXXXX\n");
	
	
	while(1)
	{	
#if	MQTT_pThread_EN	
			char *Mbox_Buf;				
			Mbox_Buf = OSMboxPend(MQTT_Tx_Box,1000,&err);
			if (OS_ERR_NONE == err)
			{
					message.payload = (void *) &Mbox_Buf[2];
					message.payloadlen = *((uint16_t *)Mbox_Buf);
					rc = aliyun_iot_mqtt_publish(&client, g_userInfo.PubTopic, &message);
	//			if (0 != rc)
	//			cnt_test++;
	//			if (cnt_test > 5)
	//			{
	//					aliyun_iot_mqtt_release(&client);
	//					printf("ali_iot_mqtt_publish failed ret = %d\n", rc);
	//					return rc;
	//			}
			}	
			OSSemPend(NetworkReset_Sem, 1, &err);
			if (OS_ERR_NONE == err)
			{
					aliyun_iot_mqtt_release(&client);
					printf("ali_iot_mqtt_publish failed ret = %d\n", rc);
					MCU_Reset();
					return rc;					
			}	
#else		
			char *Mbox_Buf;	
#if 1
			Mbox_Buf = OSMboxAccept(MQTT_Tx_Box);
			if (Mbox_Buf != NULL)
#else			
			Mbox_Buf = OSMboxPend(MQTT_Tx_Box,1,&err);
			if (OS_ERR_NONE == err)
#endif
			{
				memcpy(MSG_Publish_Buf,Mbox_Buf,MSG_LEN_MAX);
				XRJ_Clear_UplinkBuf((UINT8*)Mbox_Buf);
				message.payload = (void *) &MSG_Publish_Buf[2];
				message.payloadlen = *((uint16_t *)MSG_Publish_Buf);
				rc = aliyun_iot_mqtt_publish(&client, g_userInfo.PubTopic, &message);
				if (0 != rc)
				{	
					cnt_Pub_False++;
					if (cnt_Pub_False > 5)
					{
						OSSemPost(NetworkReset_Sem);
						printf("ali_iot_mqtt_publish failed ret = %d\n", rc);
					}
				}	
				else
				{
					cnt_Pub_False = 0;
				}	
			}	
#if 1
			if (OSSemAccept(NetworkReset_Sem) > 0)
#else			
			OSSemPend(NetworkReset_Sem, 1, &err);
			if (OS_ERR_NONE == err)
#endif			
			{
				aliyun_iot_mqtt_release(&client);
				printf("ali_iot_mqtt_publish failed ret = %d\n", rc);
				MCU_Reset();
				return rc;					
			}	
			xrj_iot_mqtt_proc(&client,20);
#endif
		//	aliyun_iot_pthread_taskdelay(5000);
	}

}



int xrj_mqtt_client(void)
{
    printf("mqtt start !\n");
	aliyun_iot_auth_init_XRJ();  
	singleThreadDemo();
    aliyun_iot_auth_release_XRJ();
    printf("mqtt out !\n");

    return 0;
}



OS_EVENT * NetworkReset_Sem;	
OS_EVENT * MQTT_Tx_Box;

void MQTT_EVENT_Create(void)
{
	OS_CPU_SR  cpu_sr = 0u;
	OS_ENTER_CRITICAL();	
	NetworkReset_Sem = OSSemCreate(0);
	MQTT_Tx_Box = OSMboxCreate((void *)0);		
	OS_EXIT_CRITICAL();
}	

void XRJ_Protocol_MQTT_Init(void)
{
#if OS_CRITICAL_METHOD == 3u                          /* Allocate storage for CPU status register      */
    OS_CPU_SR  cpu_sr = 0u;
#endif		
	OS_ENTER_CRITICAL();
	MQTT_Tx_Box->OSEventCnt = 0;	
	MQTT_Tx_Box->OSEventPtr = (void *)0;    
	st_Tx_Data.Busy = 0;	
	OS_EXIT_CRITICAL();
}	

void XRJ_Protocol_MQTT_Release(void)
{

}


struct Tx_Data st_Tx_Data;

INT32 XRJ_Check_UplinkBuf(void)
{
INT32 ret;		
#if OS_CRITICAL_METHOD == 3u                          /* Allocate storage for CPU status register      */
    OS_CPU_SR  cpu_sr = 0u;
#endif	
	OS_ENTER_CRITICAL();	
	ret = st_Tx_Data.Busy;
	OS_EXIT_CRITICAL();
	return ret;
}


void XRJ_Set_UplinkBuf(UINT8 *msg)
{		
#if OS_CRITICAL_METHOD == 3u                          /* Allocate storage for CPU status register      */
    OS_CPU_SR  cpu_sr = 0u;
#endif	
	if (msg == st_Tx_Data.BUF)
	{
		OS_ENTER_CRITICAL();	
		st_Tx_Data.Busy = 1;
		OS_EXIT_CRITICAL();
	}
}



void XRJ_Clear_UplinkBuf(UINT8 *msg)
{
		
#if OS_CRITICAL_METHOD == 3u                          /* Allocate storage for CPU status register      */
    OS_CPU_SR  cpu_sr = 0u;
#endif	
	if (msg == st_Tx_Data.BUF)
	{
		OS_ENTER_CRITICAL();	
		st_Tx_Data.Busy = 0;
		OS_EXIT_CRITICAL();
	}	
}	

void MQTT_RxMsg_Proc(UINT8 * buf ,UINT16 len)
{
#if XRJ_Protocol_EN	
	XRJ_Receive_Proc(buf,len);
#endif
}	


INT32 XRJ_MQTT_Status_Get(void)
{	
Client *tpClientStatus = pClientStatus; 	
#if 1	
		if (tpClientStatus != NULL)
		{	
			if (aliyun_iot_mqtt_get_client_state(tpClientStatus) == CLIENT_STATE_CONNECTED)
			{
				return 0;
			}				
		}
		return -1;
#else
		
#endif		
}






void Wait_Network_Success()
{
#if Net_Type == Net_GSMWIFI	
	if (FLAG_Net_Type == Net_GSM)
	{	
		GSM_Wait_Network_Success();
	}
	else if (FLAG_Net_Type == Net_WIFI)
	{	
//		ESP8266_Wait_Network_Success(Connect_Manually,"ESP8266_TEST", "12345678");
//		ESP8266_Wait_Network_Success(Connect_Manually,"QQQQ_ACCD13", "gyx12345");	
		ESP8266_Wait_Network_Success(Connect_Airkiss,"QQQQ_ACCD13", "gyx12345");
	}
#elif 	Net_Type == Net_GSM
	GSM_Wait_Network_Success();
#elif 	Net_Type == Net_WIFI
	ESP8266_Wait_Network_Success(Connect_Manually,"ESP8266_TEST", "12345678");	
//	ESP8266_Wait_Network_Success(Connect_Manually,"QQQQ_ACCD13", "gyx12345");
#elif 	Net_Type == Net_LAN
	
#if OS_CRITICAL_METHOD == 3u                          /* Allocate storage for CPU status register      */
    OS_CPU_SR  cpu_sr = 0u;
#endif
	UINT8	status;	
	while(1)
	{
		OS_ENTER_CRITICAL();
		status = lwipdev.dhcpstatus;
		OS_EXIT_CRITICAL();
		if (status == 2)
		{
			break;
		}	
		OSTimeDlyHMSM(0,0,1,0);	
	}	
#endif	
}	


void Mqtt_task(void *pdata)
{
	#if XRJ_Protocol_EN		
	XRJ_Protocol_Init();
	#endif
	
	MQTT_EVENT_Create();
	#if Net_Type == Net_GSMWIFI
	GSM_Creare_Sem_Init();
	GSM_ResetPin_Init();
	
	ESP8266_ResetPinInit();
	Wifi_Create_Sem_Init();
	
	#elif 	Net_Type == Net_GSM
	GSM_Creare_Sem_Init();
	GSM_ResetPin_Init();
	#elif 	Net_Type == Net_WIFI
	ESP8266_ResetPinInit();
	Wifi_Create_Sem_Init();
	#endif
	
	while(1)
	{
		
		Wait_Network_Success();
		XRJ_Protocol_MQTT_Init();
		OSTimeDlyHMSM(0,0,0,500);  		
		xrj_mqtt_client();
		OSTimeDlyHMSM(0,0,0,500); 
		MCU_Reset();
 	}
}





